from typing import Generic, Type, TypeVar
from pydantic import BaseModel
from sqlalchemy import and_, insert, select
from forward.dependencies.database import db
from forward.model.schemas.lucky.activity import ActivityOutSchema, ActivitySchema
from forward.model.tables.activity import ActivityModel
from forward.model.tables.merchant import MerchantModel
from forward.utils.page_utils import PageSchema, PageUtils

T = TypeVar("T", bound=BaseModel)


class ActivityORM(Generic[T]):
    async def create(self, activity_in: ActivitySchema):
        statement = insert(ActivityModel).values(**activity_in.model_dump())
        recode = await db.execute(statement)
        return recode

    async def get_one_by_id(self, id: int) -> ActivityOutSchema | None:
        statement = select(ActivityModel).where(ActivityModel.id == id)
        recode = await db.fetch_one(statement)
        if not recode:
            return None
        return ActivityOutSchema.model_validate(recode, from_attributes=True)

    async def get_ids_by_merchant_id(self, merchant_id: int) -> list[int]:
        statement = select(ActivityModel).where(
            ActivityModel.merchant_id == merchant_id
        )
        recodes = await db.fetch_all(statement)
        if not recodes:
            return []
        return [
            ActivityOutSchema.model_validate(recode, from_attributes=True).id
            for recode in recodes
        ]

    @classmethod
    async def lists(
        cls,
        page_num: int,
        page_size: int,
        where: list = [],
        order_by: list = [ActivityModel.id.desc()],
    ) -> PageSchema[ActivityOutSchema]:
        statement = (
            select(ActivityModel, MerchantModel.name.label("merchant"))
            .where(*where)
            .outerjoin(MerchantModel, MerchantModel.id == ActivityModel.merchant_id)
            .order_by(and_(*order_by))
        )
        pagination = await PageUtils.paginate(
            db=db,
            query=statement,
            page_num=page_num,
            page_size=page_size,
            schema=ActivityOutSchema,
        )
        return pagination
